package src.C_io;

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

// 压缩流
public class Demo15 {
    public static void main(String[] args) throws IOException {
        /*
           解压缩流（ZipInputStream）：
                它是一种 字节输入流
                在压缩包中每一个文件它都是一个 ZipEntry 对象
                解压本质：把每一个ZipEntry按照层级拷贝到本地另一个文件夹中
                ps：Java只能识别 .zip 后缀的压缩包
          压缩流（ZipInputStream）：
                它是一种 字节输出流
                在文件夹中每一个文件它都是一个 ZipEntry 对象
                压缩本质：把每一个ZipEntry按照层级拷贝到本地一个压缩包中
                ps：Java只能识别 .zip 后缀的压缩包
        */

        // 解压
        //uncompress(new File("E:\\12.zip"), new File("E:\\"));

        // 压缩单个文件
        //compress(new File("E:\\12\\3\\5.txt"), new File("E:\\12\\3\\"));

        // 压缩整个文件夹
        //1、创建File对象表示要压缩的文件夹
        File src = new File("E:\\12");
        // 2、创建File对象表示压缩包的路径（直接在原文件夹的同级目录下添加）
        File dest = new File(src+".zip");
        // 3、创建压缩流关联压缩包
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));
        // 4、获取src里面的每一个文件，变成ZipEntry对象，再放入到压缩包当中
        toZip(src, zos,src.getName()); // src.getName()传被压缩的文件夹的名字
        // 5、释放资源
        zos.close();
    }

    // 解压
    public static void uncompress (File src, File dest) throws IOException {
        // 创建一个解压缩流来读取压缩包中的数据
        ZipInputStream zis = new ZipInputStream(new FileInputStream(src));
        // 获取压缩包中的文件和文件夹
        ZipEntry zipEntry;
        while ((zipEntry = zis.getNextEntry()) != null){    // 读不到东西会返回null
            if (zipEntry.isDirectory()){    // 如果是文件夹则创建
                new File(dest,zipEntry.toString()).mkdirs();
            } else {    // 如果是文件则读取写入
                FileOutputStream fos = new FileOutputStream(new File(dest,zipEntry.toString()));
                int b;
                while ((b = zis.read()) != -1){
                    fos.write(b);
                }
                fos.close();
                // 表示在压缩包中的一个文件处理完毕了
                zis.closeEntry();
            }
        }
        zis.close();
    }

    // 压缩
    public static void compress (File src, File dest) throws IOException {
        // 1、创建压缩流对象绑定写入的压缩包路径
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest,"new.zip"))); // 压缩包的父路径+名字
        // 2、创建 zipEntry 对象
        ZipEntry zipEntry = new ZipEntry("new.txt"); // 在压缩包里被压缩文件的 路径+名字（注意是有路径的ps：aa\\new.txt）
        // 3、将 zipEntry 对象放到压缩包里
        zos.putNextEntry(zipEntry);
        // 4、读取文件中的内容，并写入新文件
        FileInputStream fis = new FileInputStream(src);
        int b;
        while ((b = fis.read()) != -1){
            zos.write(b);
        }
        zos.closeEntry();
        zos.close();
    }

    // 数据源 压缩流 压缩包内部路径
    public static void toZip(File src, ZipOutputStream zos, String name) throws IOException {
        File[] files = src.listFiles();
        for (File file : files){
            if (file.isFile()){  // 是文件则变成zipEntry对象，放入压缩包中
                ZipEntry zipEntry = new ZipEntry(name + "\\" + file.getName()); // 重要
                zos.putNextEntry(zipEntry);
                FileInputStream fis = new FileInputStream(file);
                int b;
                while ((b = fis.read()) != -1){
                    zos.write(b);
                }
                fis.close();
                zos.closeEntry();
            } else { // 不是文件则递归
                toZip(file, zos, name + "\\" + file.getName());
                // 有个bug当时没解决，就是最底层的空文件夹没有被压缩
            }
        }
    }
}
